#include "header.h"

void *child(void *ptr)																// Child thread created from Server
{
	//printf("Child Thread CREATED\n");
	int childDesc = (int) ptr;
	printf("Child desc = %d\n",childDesc);	

	pthread_t readThread;															// Read thread to receive the data coming from each node
	pthread_t writeThread;															// write therad to send the data going to each node


	Header recHeader;																			// RECEIVE HEADER

	char recHeaderBuffer[28];
	memset(recHeaderBuffer,'\0',28);
	int recHeaderBytes = recv(childDesc,&recHeaderBuffer,27,0);
	if(recHeaderBytes != 27)
	{
		//printf("Header was not comepletely received\n");
		pthread_exit(NULL);
	}
	recHeaderBuffer[strlen(recHeaderBuffer)+1] = '\0';
	printf("Header Received\n");

	recHeader.uoid = (unsigned char *)malloc(20* sizeof(char));
	memcpy(&recHeader.messageType,&ntohs(recHeaderBuffer[0]),1);
	memcpy(recHeader.uoid,&recHeaderBuffer[1],20);
	memcpy(&recHeader.ttl,&ntohs(recHeaderBuffer[21]),1);
	memcpy(&recHeader.reserved,&ntohs(recHeaderBuffer[22]),1);
	memcpy(&recHeader.dataLength,&ntohl(recHeaderBuffer[23]),4);
		
		
	//printf("Type = 0x%02x\n",recHeader.messageType);
	//printUOID(recHeader.uoid);
	////printf("TTL = %hhu\n",recHeader.ttl);
	////printf("Reserved = %hhu\n",recHeader.reserved);
	////printf("Datalength = %u\n",recHeader.dataLength);

	if(recHeader.messageType == helloMessageType)										// helloMessageType == 0xfa
	{
		printf("Hello msg\n");																	// RECEIVE HELLO MESSAGE
		HelloMessage recHello;
		char recMessageBuffer[recHeader.dataLength+1];
		memset(recMessageBuffer,'\0',(recHeader.dataLength+1)*sizeof(char));
		int revMsgBytes = recv(childDesc,&recMessageBuffer,recHeader.dataLength,0);				
		if(revMsgBytes != (int)recHeader.dataLength)
		{
			printf("Msg was not completely received\n");
			pthread_exit(NULL);
		}
		recMessageBuffer[strlen(recMessageBuffer)+1] = '\0';
		printf("Message Received = %s---\n",recMessageBuffer);
		//printf("Bytes received = %d\n",a);
			
		
		recHello.hostname = (char *)malloc((recHeader.dataLength-1) * sizeof(char));
		memset(recHello.hostname,'\0',(recHeader.dataLength-1) * sizeof(char));
		memcpy(&recHello.port,&ntohs(recMessageBuffer[0]),2);
		memcpy(recHello.hostname,&recMessageBuffer[2],recHeader.dataLength-2);
		recHello.hostname[strlen(recHello.hostname)+1] = '\0';
		
		////printf("Buffer -------------> %c--- \n",recMessageBuffer[15]);
		
		//printf("Received Hello Host name = %s---\n",recHello.hostname);
		//printf("Received Hello Port = %hu\n",recHello.port);
		////printf("HOST NAME  =%s---\n",recHello.hostname);

		Messages msg;
		msg.Header = (char *)malloc(28*sizeof(char));
		memset(msg.Header,'\0',28);
		msg.Data = (char *)malloc(512*sizeof(char));
		memset(msg.Data,'\0',512);
		memcpy(&msg.Header[0],&recHeaderBuffer[0],27);
		memcpy(&msg.Data[0],&recHello.port,2);
		memcpy(&msg.Data[2],&recHello.hostname[0],13);
		struct timeval t;
		gettimeofday(&t, NULL);
		enterLogMessage(msg,'r',t);
																											// SEND HELLO HEADER 
		
		unsigned int dataLength = (uint32_t)(sizeof(uint16_t)+ strlen(node.getHostName()));				// data length for hello
		Header sendHeader = createHeader((uint8_t)helloMessageType, dataLength);
	
	
	
		//printf("Type = 0x%02x\n",sendHeader.messageType);
		//printUOID(sendHeader.uoid);
		////printf("TTL = %hhu\n",sendHeader.ttl);
		////printf("Reserved = %hhu\n",sendHeader.reserved);
		//printf("Datalength = %u\n",sendHeader.dataLength);
	
		char sendheaderBuffer[28];
		memset(sendheaderBuffer,'\0',28);
		memcpy(&sendheaderBuffer[0],&htons(sendHeader.messageType),1);
		memcpy(&sendheaderBuffer[1],sendHeader.uoid,20);
		memcpy(&sendheaderBuffer[21],&htons(sendHeader.ttl),1);
		memcpy(&sendheaderBuffer[22],&htons(sendHeader.reserved),1);
		memcpy(&sendheaderBuffer[23],&htonl(sendHeader.dataLength),4);
		sendheaderBuffer[strlen(sendheaderBuffer)+1] = '\0';
		int sendHeaderBytes = send(childDesc,&sendheaderBuffer,27,0);	
		if(sendHeaderBytes != 27)
		{
			//printf("Header was not completely sent\n");
			pthread_exit(NULL);
		}
		printf("Header Sent\n");
								

																								// SEND HELLO MESSAGE
		HelloMessage helloMsg = sendHello();

		char sendMessageBuffer[sendHeader.dataLength+1];
		memset(sendMessageBuffer,'\0',(sendHeader.dataLength+1)*sizeof(char));
		memcpy(&sendMessageBuffer[0],&htons(helloMsg.port),2);
		memcpy(&sendMessageBuffer[2],(char *)helloMsg.hostname,strlen(helloMsg.hostname));
		sendMessageBuffer[strlen(sendMessageBuffer)+1] = '\0';
		////printf("helloMsg.hostname = %d\n",strlen(helloMsg.hostname));
		printf("Sent Message is : %s\n",sendMessageBuffer);
		int sendMsgBytes = send(childDesc,&sendMessageBuffer,sendHeader.dataLength,0);																		
		if(sendMsgBytes != (int) sendHeader.dataLength)
		{
			//printf("Msg was not completely send\n");
			pthread_exit(NULL);
		}

		Messages msg1;
		msg1.Header = (char *)malloc(28*sizeof(char));
		memset(msg1.Header,'\0',28);
		msg1.Data = (char *)malloc(512*sizeof(char));
		memset(msg1.Data,'\0',512);
		memcpy(&msg1.Header[0],&sendMessageBuffer[0],27);
		memcpy(&msg1.Data[0],&helloMsg.port,2);
		memcpy(&msg1.Data[2],&helloMsg.hostname[0],13);
		struct timeval t1;
		gettimeofday(&t1, NULL);
		enterLogMessage(msg1,'s',t1);
		
		pthread_mutex_lock(&NeighborList);																//Apply LOCK for adding in getNeighborList()
		
		int createFlag = 0; 
		char hostNamePort[100];
		memset(hostNamePort,'\0',100*sizeof(char));
		////printf("HOST NAME  =%s---\n",recHello.hostname);
		sprintf(hostNamePort,"%s:%u",recHello.hostname,recHello.port);										//concat senders host name and port by :
		

		multimap<string,int> tempMultiMap = node.getNeighborList();
		list<int> tempList = node.getRemoveConnectionList();

		if(tempMultiMap.find(hostNamePort)->second == tempMultiMap.end()->second)		//IF equal Entry NOT FOUND
		{
			printf("1 hostNamePort = %s\n",hostNamePort);
			tempMultiMap.insert(pair<string,int>(hostNamePort,childDesc));							//if not found, add to neighborList
			createFlag = 1;
			printf("Node not found. Node Added\n");
		}
		else
		{
																											// IF PRESENT, TIE BREAKER, // As it is already present, the previously added node would be added by client of THIS NODE		
			if(node.getPort() > recHello.port)																							
			{
				printf("Do nothing - 1\n");
				//Do nothing because there is already a connection made by this node (in Connection Thread)
			}
			else if(node.getPort() < recHello.port)
			{

				
				int temp = tempMultiMap.find(hostNamePort)->second;
				////printf("11 hostNamePort = %s\n",hostNamePort);
				tempList.push_back(temp);			//add the sockdesc (for read and write thread) to this list which you want to cancel due to duplicate connection


				tempMultiMap.erase(tempMultiMap.find(hostNamePort));			//erase neighbor node with sockdesc
				
				tempMultiMap.insert(pair<string,int>(hostNamePort,childDesc));			//add neighbor with THIS sockdesc
				createFlag = 1;
			}
			else
			{
				if(strcmp(node.getHostName(),recHello.hostname) > 0)
				{
					//printf("Do nothing\n");
					//Do nothing because there is already a connection made by this node (in Connection Thread)
				}
				else if(strcmp(node.getHostName(),recHello.hostname) < 0)
				{
					////printf("12 hostNamePort = %s\n",hostNamePort);
					int temp = tempMultiMap.find(hostNamePort)->second;
					tempList.push_back(temp);			//add the sockdesc (for read and write thread) to this list which you want to cancel due to duplicate connection


					tempMultiMap.erase(tempMultiMap.find(hostNamePort));			//erase neighbor node with sockdesc
				
					tempMultiMap.insert(pair<string,int>(hostNamePort,childDesc));			//add neighbor with THIS sockdesc
					createFlag = 1;
				}
			}
		}
	
		node.setNeighborList(tempMultiMap);
		node.setRemoveConnectionList(tempList);

		printf("SIZE AFTER ADDING = %d\n",	node.getNeighborList().size());

		pthread_mutex_unlock(&NeighborList);															//Release LOCK for adding in getNeighborList()

		if(createFlag == 1)																			// if your port number and hostname are less then othernode you have to create threds here
		{
			pthread_mutex_lock(&deleteConnectionLock[childDesc]);	
			deleteConnection[childDesc] = false;
			pthread_mutex_unlock(&deleteConnectionLock[childDesc]);	

			iretReadThread = pthread_create(&readThread, NULL, read, (void *) childDesc);
			iretWriteThread = pthread_create(&writeThread, NULL, write, (void *)childDesc);
			iretKeepAliveThread = pthread_create(&keepAliveThread, NULL, keepAlive, (void *)childDesc);

				
			//pthread_join( readThread, NULL);
			//pthread_join( writeThread, NULL);
			//pthread_join( keepAliveThread,NULL);
		}
		free(sendMessageBuffer);
		free(recMessageBuffer);
	}

	else if(recHeader.messageType == joinRequestMessageType)
	{
		printf("Join Request\n");
																									//RECEIVE JOIN REQUEST MESSAGE
		char recMessageBuffer[recHeader.dataLength+1];
		memset(recMessageBuffer,'\0',(recHeader.dataLength+1)*sizeof(char));
		int receivedBytes = recv(childDesc,&recMessageBuffer,recHeader.dataLength,0);	
		if(receivedBytes != (int)recHeader.dataLength)
		{
			//printf("Msg was not completely received\n");
			pthread_exit(NULL);
		}
		recMessageBuffer[strlen(recMessageBuffer)+1] = '\0';
		//printf("Message Received = %d\n",receivedBytes);
		////printf("%x-%x-%x-%x-\n",recMessageBuffer[0],recMessageBuffer[1],recMessageBuffer[2],recMessageBuffer[3]);

		char *tempHeader = (char *)malloc(28*sizeof(char));
		memset(tempHeader,'\0',28);
		memcpy(&tempHeader[0],&recHeader.messageType,1);
		memcpy(&tempHeader[1],recHeader.uoid,20);
		memcpy(&tempHeader[21],&recHeader.ttl,1);
		memcpy(&tempHeader[22],&recHeader.reserved,1);
		memcpy(&tempHeader[23],&recHeader.dataLength,4);

		////printf("Message TYPE = %x-%x-%x-%x\n",tempHeader[0],tempHeader[1],tempHeader[2],tempHeader[3]);




		Messages msg;
		msg.socketDescripter = childDesc;
		msg.Header = (char*)malloc(28*sizeof(char));
		memcpy(msg.Header,tempHeader,28);
		msg.Data = (char*)malloc(recHeader.dataLength*sizeof(char));
		memcpy(msg.Data,&recMessageBuffer,recHeader.dataLength);


		pthread_mutex_lock(&ReadQueue);																//APPLY LOCK
			
		readQueue.push_back(msg);															// msg added to READ QUEUE WITHOUT ntohs
		pthread_cond_signal(&condition_var_Read);	
		////printf("Read Queue Size = %d\n",readQueue.size());
			
		pthread_mutex_unlock(&ReadQueue);														//Release LOCK

		pthread_mutex_lock(&deleteConnectionLock[childDesc]);	
		deleteConnection[childDesc] = false;
		pthread_mutex_unlock(&deleteConnectionLock[childDesc]);	

		iretReadThread = pthread_create(&readThread, NULL, read, (void *) childDesc);
		iretWriteThread = pthread_create(&writeThread, NULL, write, (void *)childDesc);
		//pthread_join( writeThread, NULL);


	}
	//printf("Child Thread EXIT\n");
	return NULL;
}

